package com.happycat.interceptor;

import com.alibaba.fastjson.JSON;
import com.happycat.ResponseHeaderModel;
import com.happycat.SysContants;
import com.happycat.base.context.BaseContextHandler;
import com.happycat.config.Audience;
import com.happycat.config.HappyCatConfigarution;
import com.happycat.config.HappyCatSecurity;
import com.happycat.mobile.service.UserAccountService;
import com.happycat.mobile.service.UserMenuService;
import com.happycat.utils.JwtTokenUtil;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JwtInterceptor implements HandlerInterceptor {

	@Autowired
    private Audience audience;

	@Autowired
	private UserMenuService userMenuService;

	@Autowired
	private UserAccountService userAccountService;

	@Autowired
	private HappyCatConfigarution happyCatConfigarution;

    @Autowired
    private HappyCatSecurity happyCatSecurity;

	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException{
		// 忽略带JwtIgnore注解的请求, 不做后续token认证校验
        if (HttpMethod.OPTIONS.matches(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }
        String url = request.getRequestURI();

        log.info("请求url:{}", url);

        // 忽略 token 认证的接口
//        if (isIgnoreToken(url)) {
//            log.debug("access filter not execute, uri:{}", url);
//            return true;
//        }

        // 获取请求头信息authorization信息
        final String authHeader = request.getHeader("token");

//        if(StringUtils.isBlank(authHeader)) {
//            return true;
//        }
//        if("Bearer".equals(authHeader.trim())) {
//            return true;
//        }

        if (StringUtils.isBlank(authHeader)) {
            log.error("token为空");
        	ResponseHeaderModel responseHeaderModel = new ResponseHeaderModel();
    		responseHeaderModel.setCode(SysContants.SYS_FAIL_CODE);
    		responseHeaderModel.setMessage("token为空！");
    		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    		response.getOutputStream().write(JSON.toJSONString(responseHeaderModel).getBytes());
    		return false;
        }
        // 验证token是否有效--无效已做异常抛出，由全局异常处理后返回对应信息
//        Claims claims = null;
        try {
        	JwtTokenUtil.parseJWT(authHeader, audience.getBase64Secret());

            //设置上下文
            BaseContextHandler.setAccount(JwtTokenUtil.getUsername(authHeader, audience.getBase64Secret()));
            BaseContextHandler.setUserId(JwtTokenUtil.getUserId(authHeader, audience.getBase64Secret()));
            BaseContextHandler.setUserAccount(JwtTokenUtil.getUserAccount(authHeader, audience.getBase64Secret()));
		} catch (ExpiredJwtException jwte) {
            log.error("token过期");
			ResponseHeaderModel responseHeaderModel = new ResponseHeaderModel();
    		responseHeaderModel.setCode(SysContants.SYS_TOKEN_EXPIRED);
    		responseHeaderModel.setMessage("token已过期！");
    		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    		response.getOutputStream().write(JSON.toJSONString(responseHeaderModel).getBytes());
    		return false;
		}catch(Exception e) {
            log.error("token无效");
			ResponseHeaderModel responseHeaderModel = new ResponseHeaderModel();
    		responseHeaderModel.setCode(SysContants.SYS_FAIL_CODE);
    		responseHeaderModel.setMessage("token无效！");
    		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    		response.getOutputStream().write(JSON.toJSONString(responseHeaderModel).getBytes());
		    return false;
		}
        //输出请求日志
        // 防止流读取一次后就没有了, 所以需要将流继续写出去
//        HttpServletRequest httpServletRequest = request;
//        ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request);
//        printRequest(requestWrapper);

        //获取用户名
//        try {
//			//鉴权，查询当前url菜单的所有的角色
//			List<AccountRole> list = happyCatConfigarution.getRoleMenu().get(url);
//			//鉴权,查询当前用户的所有角色
//			List<Map<String,Object>> userRoleList = (List<Map<String,Object>>)claims.get("roles");
//			// 判断用户是否具有当前url权限
//			boolean flag = false;
//			for(Map<String,Object> accountRole: userRoleList) {
//				for(AccountRole menuRole: list) {
//					if(Long.parseLong(accountRole.get("id").toString()) ==  menuRole.getId()) {
//						flag = true;
//						break;
//					}
//				}
//				if(flag) {
//					break;
//				}
//			}
//			if(!flag) {
//				ResponseHeaderModel responseHeaderModel = new ResponseHeaderModel();
//	    		responseHeaderModel.setCode(SysContants.SYS_FAIL_CODE);
//	    		responseHeaderModel.setMessage("用户权限不足！");
//	    		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
//	    		response.getOutputStream().write(JSON.toJSONString(responseHeaderModel).getBytes());
//	    		return false;
//			}
//        } catch (Exception e) {
//        	ResponseHeaderModel responseHeaderModel = new ResponseHeaderModel();
//    		responseHeaderModel.setCode(SysContants.SYS_FAIL_CODE);
//    		responseHeaderModel.setMessage("系统接口权限未配置！");
//    		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
//    		response.getOutputStream().write(JSON.toJSONString(responseHeaderModel).getBytes());
//    		return false;
//		}
        return true;
    }

    /**
     * 忽略应用级token
     *
     * @return
     */
    protected boolean isIgnoreToken(String uri) {
        AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
        return Arrays.stream(happyCatSecurity.getAntMatchers())
                .anyMatch((url) -> uri.startsWith(url) || ANT_PATH_MATCHER.match(url, uri));
    }

    private void printRequest(ServletRequest servletRequest) {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        String requestBody = "";
        String requestContentType = request.getHeader(HttpHeaders.CONTENT_TYPE);
        if (requestContentType != null) {
            //	只拦截 json 请求的参数
            if (requestContentType.startsWith(MediaType.APPLICATION_JSON_VALUE)
                    || requestContentType.startsWith(MediaType.APPLICATION_XML_VALUE)) {
                requestBody = getRequestBody(request);
                log.info("请求开始 url:{}", uri);
                log.info("请求开始 body:{}", requestBody);
            }else if(requestContentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
                showParams(request);
            }
        }
    }

    private String getRequestBody(HttpServletRequest request) {
        int contentLength = request.getContentLength();
        if (contentLength <= 0) {
            return "";
        }
        try {
            return IOUtils.toString(request.getReader());
        } catch (IOException e) {
            log.error("获取请求体失败", e);
            return "";
        }
    }

    private void showParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Enumeration paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = (String) paramNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues.length == 1) {
                if (paramValues[0].length() != 0) {
                    params.put(paramName, paramValues[0]);
                }
            }
        }
        Map<String, String> heads = new HashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String name = (String) enumeration.nextElement();
            String values = request.getHeader(name);
            heads.put(name, values);
        }

        log.info("request url:" + request.getRequestURL());
        log.info("request remoteAddr:" + request.getRemoteAddr());
        log.info("request method:" + request.getMethod());
        log.info("request header host:" + request.getHeader("Host"));
        log.info("request web contextpath:" + request.getContextPath());
        log.info("request heads:" + request.getContextPath());
        log.info("request queryString:" + request.getQueryString());
        log.info("request params:" + JSON.toJSONString(params));
    }

}
